from django.shortcuts import get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.template.defaultfilters import slugify
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage

from obviews.views import View, FormView, AjaxFormView, CutResponse
from obviews.fallbacks import HttpResponseBadRequest
from polls.published_manager import STATE_DEFAULT, STATE_PUBLISHED
from polls.models import Poll, Vote, Choice
from polls.forms import *

class PaginatedView(View):
    defaults = {"per_page": 25}

    def __init__(self, model, *args, **kwargs):
        super(PaginatedView, self).__init__(*args, **kwargs)
        self.model = model
        
    def build_params(self, request, page=None, order_by=None):
        per_page = self.params["per_page"]
        # cast page as int. do not catch ValueError (forced by URL)
        page = page and int(page) or 1
        if hasattr(self.model.objects, 'published'):
            object_list = self.model.objects.published()
        else:
            object_list = self.model.objects.all()
        # order. Again, value filtered by URL
        if order_by:
            object_list = object_list.order_by(order_by)
        paginator = Paginator(object_list, per_page)
        try:
            objects = paginator.page(page)
        except (EmptyPage, InvalidPage):
            objects = paginator.page(paginator.num_pages)
        # return built params
        return {"objects": objects,
                "sort_field": order_by}

# POLLS #########################################################
class PaginatedPollView(PaginatedView):
    template_name = "polls/poll_list.html"
    defaults = {"base_url": "poll_list"}
    
class CreatePoll(FormView):
    template_name = "polls/poll_create.html"
    login_required = True
    form_class = CreatePollFormClass
    
    def initial_data(self, request, **vars):
        poll_id = vars.get("poll_id", None)
        if poll_id is None:
            return {"initial": {'state': STATE_DEFAULT}}
        else:
            return {"instance": get_object_or_404(Poll, pk=poll_id) }

    def process_form(self, form, request, **vars):
        poll = form.save(commit=False)
        poll.user = request.user
        poll.ip_address = request.META['REMOTE_ADDR']
        poll.slug = slugify(poll.title)
        poll.save()
        return poll
        
    def on_success(self, result, request, **vars):
        if result.state != STATE_PUBLISHED:
            return HttpResponseRedirect(reverse("poll_posted"))
        else:
            return HttpResponseRedirect(reverse("poll_modify", kwargs={'poll_id':result.pk}))
        
class PostedView(View):
    template_name = "polls/poll_posted.html"
    defaults = {"p": "posted"}

class ModifyPoll(FormView):
    template_name = "polls/poll_create.html"
    login_required = True
    form_class = ModifyPollFormClass
    
    def build_params(self, request, poll_id):
        return {'poll': get_object_or_404(Poll, pk=poll_id)}
    
    def initial_data(self, request, **vars):
        return {"instance": vars["poll"]}

    def process_form(self, form, request, **vars):
        poll = form.save()
        return poll
        
    def on_success(self, result, request, **vars):
        return HttpResponseRedirect(result.get_absolute_url())
        
class DeletePoll(View):
    login_required = True
    
    def build_params(self, request, poll_id):
        poll = get_object_or_404(Poll, pk=poll_id)
        if request.user == poll.user:
            poll.delete()
            raise CutResponse(HttpResponseRedirect(reverse('poll_home')))
        else:
            raise CutResponse(HttpResponseForbidden('You must own the poll to delete it.'))
        
class ViewPoll(View):
    template_name = "polls/poll_view.html"

    def build_params(self, request, poll_id):
        poll = get_object_or_404(Poll, pk=poll_id)
        all_votes = Vote.objects.filter(poll=poll)
        my_vote = request.user.is_authenticated() and all_votes.filter(user=request.user) or False
        votes = {}
        for choice in poll.choice_set.all():
            votes[choice.choice] = all_votes.filter(choice=choice).count()
        return {'poll': poll,
                'my_vote': my_vote,
                'votes': votes}

# CHOICES ############################################################
class CreateChoice(AjaxFormView):
    template_name = "polls/choice_create.html"
    login_required = True
    form_class = CreateChoiceFormClass

    def build_params(self, request, poll_id):
        return {'poll': get_object_or_404(Poll, pk=poll_id)}
    
    def initial_data(self, request, **vars):
        return {"initial": {'poll': vars['poll'].pk}}

    def process_form(self, form, request, **vars):
        return form.save()
        
    def ajax_success(self, result, request, **vars):
        return HttpResponse('<li>%s</li>'% result.choice)
        
    def noajax_success(self, result, request, **vars):
        return HttpResponseRedirect(result.poll.get_absolute_url())

# VOTES ##############################################################
class DoVote(View):
    template_name = "polls/poll_vote.html"
    login_required = True
    
    def build_params(self, request, poll_id, choice_id):
        user = request.user
        poll = get_object_or_404(Poll, pk=poll_id)
        if user.is_authenticated() and Vote.objects.filter(poll=poll).filter(user=user):
            raise CutResponse(HttpResponse('already voted'))
        choice = get_object_or_404(Choice, pk=choice_id)
        vote = Vote(user=user, poll=poll, choice=choice,
                    ip_address=request.META['REMOTE_ADDR'])
        vote.save()
        return {'redirect': poll.get_absolute_url()}

class PaginatedVoteView(PaginatedView):
    template_name = "polls/vote_list.html"
    defaults = {"per_page": 50,
                "base_url": "votes_ordered",
                "order_by": "choice",}        
